package com.master.lib.utils

import android.app.Activity
import android.graphics.Rect
import android.view.View
import android.view.ViewTreeObserver
import android.view.Window
import android.view.inputmethod.InputMethodManager
import com.master.lib.ext.application
import kotlin.math.abs

/**
 * 软键盘工具类
 * @author: MasterChan
 * @date: 2023-01-03 15:04
 */
object KeyboardUtils {

    /**
     * 判断键盘为显示状态时，[Window.getDecorView]被遮挡的最小高度
     */
    var keyboardJudgeShowHeight = 200
    private var decorViewVisibleHeight = 0
    private const val TAG_ON_GLOBAL_LAYOUT_LISTENER = -8

    fun interface OnKeyboardChangedListener {
        fun onKeyboardChanged(isShow: Boolean, height: Int)
    }

    /**
     * 显示键盘
     * @param view 接收输入的View
     * @param flags 默认为0，[InputMethodManager.SHOW_IMPLICIT]有可能不会显示；
     * [InputMethodManager.SHOW_FORCED]强制显示
     */
    fun showKeyboard(view: View, flags: Int = 0) {
        val manager = application.getSystemService(InputMethodManager::class.java) ?: return
        view.isFocusable = true
        view.isFocusableInTouchMode = true
        view.requestFocus()
        manager.showSoftInput(view, flags)
    }

    fun hideKeyboard(view: View) {
        val manager = application.getSystemService(InputMethodManager::class.java) ?: return
        manager.hideSoftInputFromWindow(view.windowToken, 0)
    }

    fun isShown(activity: Activity): Boolean {
        return getDecorViewInvisibleHeight(activity.window) > keyboardJudgeShowHeight
    }

    /**
     * 获取[Window.getDecorView]未显示区域的高度；未显示区域为键盘遮挡，即获取的是键盘高度
     * @param window Window
     * @return Int
     */
    private fun getDecorViewInvisibleHeight(window: Window): Int {
        val decorView = window.decorView
        val outRect = Rect()
        decorView.getWindowVisibleDisplayFrame(outRect)
        return abs(decorView.bottom - outRect.bottom)
    }

    fun registerOnKeyboardChangedListener(activity: Activity, listener: OnKeyboardChangedListener) {
        activity.window.decorView.viewTreeObserver.addOnGlobalLayoutListener(
            DecorViewLayoutListener(activity, listener).apply {
                activity.window.decorView.setTag(TAG_ON_GLOBAL_LAYOUT_LISTENER, this)
            }
        )
    }

    fun unregisterOnKeyboardChangedListener(activity: Activity) {
        val decorView = activity.window.decorView
        val tag = decorView.getTag(TAG_ON_GLOBAL_LAYOUT_LISTENER)
        if (tag is ViewTreeObserver.OnGlobalLayoutListener) {
            decorView.viewTreeObserver.removeOnGlobalLayoutListener(tag)
        }
    }

    private class DecorViewLayoutListener(
        private val activity: Activity,
        private val listener: OnKeyboardChangedListener
    ) : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            activity.window.decorView.viewTreeObserver.addOnGlobalLayoutListener(object :
                ViewTreeObserver.OnGlobalLayoutListener {
                override fun onGlobalLayout() {
                    //获取当前根视图在屏幕上显示的大小
                    val rect = Rect()
                    activity.window.decorView.getWindowVisibleDisplayFrame(rect)
                    val visibleHeight = rect.height()
                    if (decorViewVisibleHeight == 0) {
                        decorViewVisibleHeight = visibleHeight
                        return
                    }

                    //根视图显示高度没有变化，可以看作软键盘显示／隐藏状态没有改变
                    if (decorViewVisibleHeight == visibleHeight) {
                        return
                    }

                    //根视图显示高度变小超过200，可以看作软键盘显示了
                    if (decorViewVisibleHeight - visibleHeight > keyboardJudgeShowHeight) {
                        listener.onKeyboardChanged(true, decorViewVisibleHeight - visibleHeight)
                        decorViewVisibleHeight = visibleHeight
                        return
                    }

                    //根视图显示高度变大超过200，可以看作软键盘隐藏了
                    if (visibleHeight - decorViewVisibleHeight > 200) {
                        listener.onKeyboardChanged(false, visibleHeight - decorViewVisibleHeight)
                        decorViewVisibleHeight = visibleHeight
                    }
                }
            })
        }
    }
}